package com.caocaog.market.finance.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caocaog.market.finance.entity.FinanceLine;
import com.caocaog.market.finance.enums.WithdrawStatus;
import com.caocaog.market.finance.enums.WithdrawType;
import com.caocaog.market.finance.mapper.FinanceLineMapper;
import com.caocaog.market.finance.service.FinanceGroupLineMergeService;
import com.caocaog.market.finance.service.FinanceLineService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CacheConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static com.caocaog.market.finance.enums.WithdrawStatus.PENDING_WITHDRAWAL;
import static com.caocaog.market.finance.enums.WithdrawType.MERCHANT;
import static com.caocaog.market.finance.enums.WithdrawType.SITE;
import static java.util.stream.Collectors.toList;

@Slf4j
@Service
@CacheConfig(cacheNames = CacheConstant.FINANCE_LINE_LIST_BY_GROUP_ID)
public class FinanceLineServiceImpl extends ServiceImpl<FinanceLineMapper, FinanceLine> implements FinanceLineService {

    @Setter(onMethod_ = @Autowired)
    private FinanceGroupLineMergeService financeGroupLineMergeService;


    @Override
    public IPage<FinanceLine> queryFinanceLinePage(Page<FinanceLine> page, FinanceLine financeLine, String siteId, String merchantId) {
        LambdaQueryWrapper<FinanceLine> queryWrapper = new LambdaQueryWrapper<FinanceLine>()
                .eq(financeLine.getSettlement() != null, FinanceLine::getSettlement, financeLine.getSettlement())
                .eq(financeLine.getShopStatus() != null, FinanceLine::getShopStatus, financeLine.getShopStatus())
                .eq(financeLine.getSiteStatus() != null, FinanceLine::getSiteStatus, financeLine.getSiteStatus());

        if (StringUtils.isNotBlank(financeLine.getPayTimeFrom()) && StringUtils.isNotBlank(financeLine.getPayTimeTo())) {
            if (financeLine.getPayTimeFrom().equals(financeLine.getPayTimeTo()))
                queryWrapper.apply("DATE_FORMAT(line.pay_time,'%Y-%m-%d') = '" + financeLine.getPayTimeFrom() + "'");
            else queryWrapper
                    .ge(FinanceLine::getPayTime, financeLine.getPayTimeFrom())
                    .le(FinanceLine::getPayTime, financeLine.getPayTimeTo());
        }
        merchantId = StringUtils.isNotBlank(merchantId) ? merchantId : financeLine.getMerchantId();
        baseMapper.queryFinanceLinePage(page, queryWrapper, siteId, merchantId, financeLine.getShopId(), financeLine.getOrderNo(), financeLine.getGroupNo(), financeLine.getSiteName());
        for (FinanceLine item : page.getRecords())
            item.calculateSystemAmount().calculateSiteAmount().calculateShopAmount().setUpdatablePCT();
        return page;
    }


    @Override
    public Integer createFinanceLine(FinanceLine financeLine) {
        return baseMapper.insert(financeLine);
    }


    @Override
    @CacheEvict(allEntries = true)
    public Integer updateFinanceLine(FinanceLine financeLine) {
        return baseMapper.updateById(financeLine.clearFields());
    }


    @Override
    @Cacheable(key = "#groupId")
    public List<FinanceLine> getFinanceLineListByGroupId(Long groupId) {
        List<Long> lineIds = financeGroupLineMergeService.getLineIds(groupId);
        List<FinanceLine> financeLines = baseMapper.selectList(new LambdaQueryWrapper<FinanceLine>().in(FinanceLine::getId, lineIds));
        financeLines.forEach(financeLine -> financeLine
                .calculateSystemAmount()
                .calculateSiteAmount()
                .calculateShopAmount()
                .setUpdatablePCT());

        return financeLines;
    }


    @Override
    public List<FinanceLine> findNeedSettlement(int settlementDay) {
        long now = new Date().getTime();
        long settlementMilliseconds = (long) settlementDay * 24 * 60 * 60 * 1000;
        // 当前时间倒退settlementDay天
        Date settlementTime = new Date(now - settlementMilliseconds);
        // settlementDate格式化yyyy-MM-dd 00:00:00
        String settlementTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(settlementTime);

        return baseMapper.findNeedSettlement(settlementTimeStr, 3);
    }


    @Override
    public Integer updateFinanceLineSettled(List<Long> ids) {
        return baseMapper.update(null, new LambdaUpdateWrapper<FinanceLine>()
                .set(FinanceLine::getSettlement, Boolean.TRUE)
                .in(FinanceLine::getId, ids));
    }


    @Override
    public Integer updateFinanceLineStatus(List<Long> ids, WithdrawType type, WithdrawStatus status) {
        return updateFinanceLineStatus(ids, type, status, null);
    }


    @Override
    @CacheEvict(key = "#groupId")
    public Integer updateFinanceLineStatus(List<Long> ids, WithdrawType type, WithdrawStatus status, Long groupId) {
        LambdaUpdateWrapper<FinanceLine> wrapper = new LambdaUpdateWrapper<FinanceLine>().in(FinanceLine::getId, ids);

        if (type == MERCHANT) {
            wrapper.set(FinanceLine::getShopStatus, status);
        } else if (type == SITE) {
            wrapper.set(FinanceLine::getSiteStatus, status);
        }

        return baseMapper.update(null, wrapper);
    }


    /**
     * 根据ids获取对应类型未提现的实体数量
     */
    @Override
    public Boolean checkFinanceLineUnWithdrawCount(List<Long> ids, WithdrawType type) {
        // 未提现、驳回、转账失败
        Integer count = baseMapper.selectFinanceLineUnWithdrawCount(ids, type.getCode(), PENDING_WITHDRAWAL.getCode());
        return count == ids.size();
    }


    public List<String> getFinanceLineShopIds(List<Long> ids) {
        return baseMapper.getFinanceLineShopIds(ids);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public FinanceLine getFinanceLineByOrderId(String orderId) {
        FinanceLine financeLine = null;
        LambdaQueryWrapper<FinanceLine> wrapper = new LambdaQueryWrapper<FinanceLine>().eq(FinanceLine::getOrderId, orderId);
        try {
            financeLine = baseMapper.selectOne(wrapper);
        } catch (Exception e) {
            List<FinanceLine> financeLines = baseMapper.selectList(wrapper);
            if (financeLines.size() > 1) {
                log.error("结算行中订单号重复，执行删除操作");
                baseMapper.deleteBatchIds(financeLines.stream().map(FinanceLine::getId).collect(toList()).subList(1, financeLines.size()));
            }
        }

        return financeLine;
    }


    @Override
    public Integer deleteFinanceLineByOrderId(String orderId) {
        return baseMapper.delete(new LambdaQueryWrapper<FinanceLine>().eq(FinanceLine::getOrderId, orderId));
    }

}
